package sf.database.mapper;

import sf.spring.boot.system.JavaVersion;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class DefaultMethodInvokeNoCache {
    /**
     * 若jdk版本在1.8以上，且被调用的方法是默认方法，直接调用默认实现
     * 性能不佳,可以通过接口实现类,然后在接口上写对应的默认方法,此处实现仅仅是为了兼容写法.
     * @param proxy
     * @param method
     * @param args
     * @return
     */
    public static Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
        //https://dzone.com/articles/correct-reflective-access-to-interface-default-methods
        //https://gist.github.com/lukaseder/f47f5a0d156bf7b80b67da9d14422d4a
        //如何优化？
        if (JavaVersion.getJavaVersion() == JavaVersion.EIGHT) {
            final Class<?> clazz = method.getDeclaringClass();
            Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class);
            constructor.setAccessible(true);
            return constructor.newInstance(clazz)
                    .in(clazz)
                    .unreflectSpecial(method, clazz)
                    .bindTo(proxy)
                    .invokeWithArguments(args);
        } else {
            //高于java8？
            return MethodHandles.lookup()
                    .findSpecial(
                            method.getDeclaringClass(),
                            method.getName(),
                            MethodType.methodType(method.getReturnType(), method.getParameterTypes()),
                            method.getDeclaringClass())
                    .bindTo(proxy)
                    .invokeWithArguments(args);
        }
    }
}
